
import os
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import keyboard

sys.path.append(os.path.dirname(__file__)+"/../uiprototype_convert")
import makeui

context = None
g_cur_select_node = None

def init(context_):
    global context
    context = context_


class NewProjectDialog(QDialog):
    def __init__(self):
        super().__init__()

        self.str_porject_name = ""
        self.str_project_dir  = ""

        self.setWindowTitle("New Project")

        self.projectname_edit = QLineEdit()
        self.projectdir_edit  = QLineEdit()
        button_ok = QPushButton("OK")
        cancel_ok = QPushButton("Cancel")
        selectdir_edit   = QPushButton("...")

        vlayout = QVBoxLayout()
        hlayout = QHBoxLayout()
        h2layout = QHBoxLayout()
        h2layout.addWidget(self.projectdir_edit)
        h2layout.addWidget(selectdir_edit)


        layout = QFormLayout()
        layout.addRow("项目名称:", self.projectname_edit)
        layout.addRow("项目目录:", h2layout)

        hlayout.addStretch(1)
        hlayout.addWidget(button_ok)
        hlayout.addWidget(cancel_ok)

        vlayout.addLayout(layout)
        vlayout.addLayout(hlayout)

        self.setLayout(vlayout)

        button_ok.clicked.connect(self.accept)
        cancel_ok.clicked.connect(self.reject)
        selectdir_edit.clicked.connect(self.select_dir)
    
    def accept(self):
        # 判断是否填写完整
        project_name = self.projectname_edit.text()
        project_dir  = self.projectdir_edit.text()

        project_name = project_name.strip()
        project_dir  = project_dir.strip()

        if project_name == "" or project_dir == "":
            QMessageBox.information(None, "New Project", "Input is invalid!")
            return 

        self.str_porject_name = project_name
        self.str_project_dir  = project_dir
        
        super().accept()
    
    def select_dir(self):
        # 选择目录 
        dir_select = QFileDialog.getExistingDirectory(self, "Project Dir Select", "Project Dir Select")
        self.projectdir_edit.setText(dir_select)

# 框架菜单注册
#  文件|新建   文件|打开   文件|保存   文件|另存为   文件|关闭
class UIMainFileMenu:
    def __init__(self):
        self._file = None
    def priorty(self):
        return 1000
    def add_menu(self, menu_bar):
        self.file_menu = menu_bar.addMenu("File")

        self.action0 = QAction(QIcon(os.path.dirname(__file__) + "/images/xinjianmulu.png"),"New")
        self.action0.triggered.connect(self.newproject)
        self.file_menu.addAction(self.action0)

        self.action1 = QAction(QIcon(os.path.dirname(__file__) + "/images/dakaiwenjian.png"),"Open")
        self.action1.triggered.connect(self.open)
        self.file_menu.addAction(self.action1)
        

        self.action2 = QAction(QIcon(os.path.dirname(__file__) + "/images/baocun-tianchong.png"),"Save")
        self.action2.triggered.connect(self.save)
        self.file_menu.addAction(self.action2)

        self.action3 = QAction(QIcon(os.path.dirname(__file__) + "/images/baocunbingxiayibu.png"),"Save As")
        self.action3.triggered.connect(self.saveas)
        self.file_menu.addAction(self.action3)

        self.action4 = QAction(QIcon(os.path.dirname(__file__) + "/images/guanbi.png"),"Close")
        self.action4.triggered.connect(self.close)
        self.file_menu.addAction(self.action4)

    def add_toolbar(self, toolBar):
        action = toolBar.addAction(QIcon(os.path.dirname(__file__) + "/images/xinjianmulu.png"),"New")
        action.setToolTip("New")
        action.triggered.connect(self.newproject)
        action = toolBar.addAction(QIcon(os.path.dirname(__file__) + "/images/dakaiwenjian.png"),"Open")
        action.setToolTip("Open")
        action.triggered.connect(self.open)
        action = toolBar.addAction(QIcon(os.path.dirname(__file__) + "/images/baocun-tianchong.png"),"Save")
        action.setToolTip("Save")
        action.triggered.connect(self.save)
        action = toolBar.addAction(QIcon(os.path.dirname(__file__) + "/images/baocunbingxiayibu.png"),"Save As")
        action.setToolTip("Save As")
        action.triggered.connect(self.saveas)
        action = toolBar.addAction(QIcon(os.path.dirname(__file__) + "/images/guanbi.png"),"Close")
        action.setToolTip("Close")
        action.triggered.connect(self.close)

    def newproject(self, obj):
        global context

        # 新建项目菜单
        dlg = NewProjectDialog()
        re = dlg.exec()
        if re != QDialog.Accepted :
            return 

        # 新建项目
        str_project_path = dlg.str_project_dir + "/" + dlg.str_porject_name + "/"
        os.mkdir(str_project_path)

        str_resource_path = str_project_path + "resource/"
        os.mkdir(str_resource_path)

        data_service = context.find_service("DataService")
        root_node =  data_service.root_node()
        if root_node:
            QMessageBox.information(None, "New Project", "You should close project first!")
            return 

        data_service.create_rootnode(dlg.str_porject_name)
        data_service.save(str_project_path + "/" + "project.bbui")
    def saveas(self, obj):
        global context
        data_service = context.find_service("DataService")

        fileName, ok = QFileDialog.getSaveFileName(None, "Save Project", "", "bbui Project Files (*.bbui)")
        if not fileName:
            return 

        data_service.save(fileName)
        self._file = fileName
    def save(self, obj):
        global context
        data_service = context.find_service("DataService")
        
        save_file = data_service.project_file()
        if save_file != "":
            data_service.save(save_file)
        else :
            self.saveas("")
    def open(self, obj):
        fileName, ok = QFileDialog.getOpenFileName(None, "Open Project", "", "bbui Project Files (*.bbui)")
        if not fileName:
            return 

        global context
        data_service = context.find_service("DataService")
        data_service.load(fileName)
        self._file = fileName
    def close(self, obj):
        global context
        data_service = context.find_service("DataService")
        data_service.close()


class UIMainAddPageMenu:
    def __init__(self):
        self._file = None
    def add_toolbar(self, toolBar):
        toolBar.addSeparator()

        action = toolBar.addAction(QIcon(os.path.dirname(__file__) + "/images/xinjiantianjia.png"),"Add Page")
        action.setToolTip("New")
        action.triggered.connect(self.add_page)

    def add_page(self, obj):
        global context

        data_service = context.find_service("DataService")
        root_node =  data_service.root_node()
        if not root_node:
            QMessageBox.information(None, "Please create project first!", "Add page")
            return 

        new_node = data_service.create_node("Page", "MyPage")
        root_node.add_child(new_node)

class UIResourceDrag:
    def dragMoveEvent(self,event, nodes, target_node):
        #print("in dragMoveEvent ......")
        if len(nodes) != 1:
            return 
        node = nodes[0]

        if not(node.get_kind() == "Resource" and target_node.get_kind() == "Widget"):
            #print('return 0')
            return 0

        url = node.get_prop('url')
        widget_class = target_node.get_prop('class')

        # 判断是否可以拖动
        # 图片->Button  Menu  ToolBarItem   Label
        # StyleSheet -> Widget( setStyleSheet)
        url_ext = url.split('.')[-1]
        if url_ext in ['jpg', 'bmp', 'png', 'jpeg', 'gif']:
            if widget_class in ['QPushButton', 'QMenu', 'QLabel', 'NToolBarItem']:
                #print('return 1')
                return 1
            else:
                #print('return 0')
                return 0
        elif url_ext in ['qss']:
            if 'QWidget::StyleSheet' in target_node.get_props():
                #print('return 1')
                return 1
            elif 'Data::BindText' in target_node.get_props():
                return 1
            else:
                #print('return 0')
                return 0
        elif url_ext in ['json']:
            if 'Data::BindData' in target_node.get_props():
                return 1
            elif 'Data::BindText' in target_node.get_props():
                return 1
            else:
                #print('return 0')
                return 0
        else:
            if 'Data::BindText' in target_node.get_props():
                return 1
            else:
                #print('return 0')
                return 0

        #print('return 0')
        return 0
    def dropEvent(self, event, nodes, target_node):
        if len(nodes) != 1:
            return 
        node = nodes[0]

        if not(node.get_kind() == "Resource" and target_node.get_kind() == "Widget"):
            return 0

        url = node.get_prop('url')
        widget_class = target_node.get_prop('class')

        # 

        # 判断是否可以拖动
        # 图片->Button  Menu  ToolBarItem   Label
        # StyleSheet -> Widget( setStyleSheet)
        url_ext = url.split('.')[-1]
        if url_ext in ['jpg', 'bmp', 'png', 'jpeg', 'gif']:
            if widget_class in ['QPushButton', 'QMenu', 'QLabel', 'NToolBarItem']:
                # 执行拖动
                if widget_class == 'QLabel':
                    target_node.set_prop('QLabel::Pixmap', '%PROJECTPATH%/resource' + url)
                elif widget_class == 'QPushButton':
                    target_node.set_prop('QAbstractButton::Icon', '%PROJECTPATH%/resource' + url)
                elif widget_class == 'NToolBarItem':
                    target_node.set_prop('NToolBarItem::Icon', '%PROJECTPATH%/resource' + url)
                elif widget_class == 'QMenu':
                    target_node.set_prop('Data::Icon', '%PROJECTPATH%/resource' + url)
                return 1
            else:
                return 0
        elif url_ext in ['qss']:
            if 'QWidget::StyleSheet' in target_node.get_props():
                target_node.set_prop('QWidget::StyleSheet', '%PROJECTPATH%/resource' + url)
                return 1
            elif 'Data::BindText' in target_node.get_props():
                target_node.set_prop('Data::BindText', '%PROJECTPATH%/resource' + url)
                return 1
            else:
                return 0
        elif url_ext in ['json']:
            if 'Data::BindData' in target_node.get_props():
                target_node.set_prop('Data::BindData', '%PROJECTPATH%/resource' + url)
                return 1
            elif 'Data::BindText' in target_node.get_props():
                target_node.set_prop('Data::BindText', '%PROJECTPATH%/resource' + url)
                return 1
            else:
                return 0
        else:
            if 'Data::BindText' in target_node.get_props():
                target_node.set_prop('Data::BindText', '%PROJECTPATH%/resource' + url)
                return 1
            else:
                return 0

        return 0    

class ActionNewNode:
    def __init__(self, kind, parent = None):
        self._kind = kind
        self._parent = parent
    def get_name(self, kind):
        text, ok = QInputDialog().getText(None, "input "+kind+"'s name", "name:", QLineEdit.Normal)
        return text, ok
    def on_new_node(self, value):
        global context

        print("on_new_node")

        name, ok = self.get_name(self._kind)
        if not (ok and name):
            return 

        data_service = context.find_service("DataService")
        print(self._parent)
        if not self._parent:
            # 创建根节点
            new_node = data_service.create_rootnode(name)
        else:
            # 创建子节点
            new_node = data_service.create_node(self._kind, name)
            self._parent.add_child(new_node)
    def on_delete(self, value):
        print("on_delete:", self._parent)
        self._parent.delete()
    def on_rename(self, value):
        new_name, ok  = self.get_name(self._kind)
        if not (ok and new_name):
            return 
        self._parent.set_name(new_name)

class DataExploreBasicOpMenu:
    def __init__(self):
        self.menus = []
    def add_menu(self, menu, node):
        self.menus = []

        if node == None:
            obj = ActionNewNode("")
            action = menu.addAction("新建根节点2")
            action.triggered.connect(obj.on_new_node)
            self.menus.append(obj)
        else:
            kind = ""
            if node != None:
                kind = node.get_kind()
            
            kinds =  node.get_child_kinds()
            for k in kinds:
                action = menu.addAction("新建"+k)
                
                obj = ActionNewNode(k, node)
                self.menus.append(obj)
                action.triggered.connect(obj.on_new_node)

            obj = ActionNewNode(kind, node)
            self.menus.append(obj)
            action = menu.addAction("删除")
            action.triggered.connect(obj.on_delete)

            obj = ActionNewNode(kind, node)
            self.menus.append(obj)
            action = menu.addAction("重命名")
            action.triggered.connect(obj.on_rename)

class ActionNewWidget:
    def __init__(self):
        self._node = None
        self._new_type = ""

    def __del__(self):
        pass

    def on_add_widget2(self):
        # 支持四种模式
        # 单选，添加新控件到当前选择控件下
        # 多选，添加选择控件到新控件下
        # 单选，添加新控件到当前选择控件前
        # 单选，添加新控件到当前选择控件后
        # 单选，添加新控件替换当前选择控件，保留所有子节点，如果使用者本意是替换所有节点（包含子节点），那么应该向前插入，然后删除本节点


        global context
        global g_cur_select_node

        if not g_cur_select_node:
            return 
        # 为了可以让操作更容易理解，只支持针对一个节点进行操作
        if len(g_cur_select_node) == 0:
            return 

        # 获取当前键盘按键状态
        cur_select = g_cur_select_node[0]
        add_type = "child"
        parent_node = cur_select
        child_node  = None

        print('ctrl:', keyboard.is_pressed("ctrl"))
        print('shift:', keyboard.is_pressed("shift"))
        print('alt:', keyboard.is_pressed("alt"))
        print('ctrl:', keyboard.is_pressed("ctrl"))
        print('shift:', keyboard.is_pressed("shift"))
        print('alt:', keyboard.is_pressed("alt"))

        if keyboard.is_pressed("ctrl"):
            parent_node = cur_select.parent()
            child_node  = cur_select
            add_type    = "replace"
        elif keyboard.is_pressed("shift"):
            parent_node = cur_select.parent()
            child_node  = cur_select
            add_type    = "before"
        elif keyboard.is_pressed("alt"):
            parent_node = cur_select.parent()
            child_node  = cur_select
            add_type    = "after"

        if parent_node.get_kind() != 'Widget' and parent_node.get_kind() != 'Page':
            return 

        if len(g_cur_select_node) > 1 and add_type != "child":
            return 
        
        if add_type == "child" and len(g_cur_select_node)>1:
            parent_node = cur_select.parent()
            child_node  = cur_select
        
        # 新建组件 
        widget_sel = self._new_type
        data_service = context.find_service("DataService")
        new_node = data_service.create_node("Widget", widget_sel)
        new_node.set_prop('class', widget_sel)

        # properties
        properties = makeui.get_properties(widget_sel)
        for pro in properties:
            new_node.set_prop(pro, properties[pro]['default'])

        if add_type == "child":
            if len(g_cur_select_node) == 1:
                parent_node.add_child(new_node)
            else:
                # 当第一个选择节点前插入
                parent_node.insert_child(new_node, child_node)
                # 移动当前选择节点到新节点下 
                for node in g_cur_select_node:
                    node.parent().remove_child(node)
                    new_node.add_child(node)   
        elif add_type == "replace":
            parent_node.insert_child(new_node, child_node)
            child_nodes = child_node.get_children()
            child_nodes_c = [node for node in child_nodes]
            for child in child_nodes_c:
                child_node.remove_child(child)
                new_node.add_child(child)
            child_node.delete()
        elif add_type == "before":
            parent_node.insert_child(new_node, child_node)
        elif add_type == "after":
            parent_node.insert_child_after(new_node, child_node)

        

class WidgetExploreDock(QDockWidget):
    def __init__(self):
        super().__init__()

        self.objs = []
        self.widgets = [{"group":"Layout", "widgets":{
            'Vertical Layout': 'QVBoxLayout',
            'Horizontal Layout': 'QHBoxLayout',
            'Grid Layout': 'QGridLayout',
            'Form Layout': 'QFormLayout',
            'Space': 'NSpace',
            'Stretch': 'NStretch',
            'Form Layout Row': 'NQFormLayoutRow'
        }}
        , {"group":"Window", "widgets":{
            'Main Window': 'QMainWindow',
            'Dialog': 'QDialog'
        }}, {"group":"Menu/Tool Bar", "widgets":{
            'Menu Bar': 'QMenuBar',
            'Menu': 'QMenu',
            'Tool Bar': 'QToolBar',
            'Tool Bar Item': 'NToolBarItem',
            'Tool Bar Separator': 'NToolBarSeparator',
            'Context Menu': 'NContextMenu'
        }}, {"group":"Lines", "widgets":{
            'Vertical Line': 'EQVLine',
            'Horizontal Line': 'EQHLine'
        }},{"group":"Buttons", "widgets":{
            'Push Button': 'QPushButton',
            'Tool Button': 'QToolButton',
            'Radio Button': 'QRadioButton',
            'Check Box': 'QCheckBox',
            'Command Link Button': 'QCommandLinkButton',
            'Dialog Button Box': 'QDialogButtonBox'
        }}, {"group":"Item View", "widgets":{
            'List View': 'QListView',
            'Tree View': 'QTreeView',
            'Table View': 'QTableView',
            'Column View': 'QColumnView'
        }}, {"group":"Containers", "widgets":{
            'Group Box': 'QGroupBox',
            'Scroll Area': 'QScrollArea',
            'Tool Box': 'QToolBox',
            'Tab Widget': 'QTabWidget',
            'Stacked Widget': 'QStackedWidget',
            'Frame': 'QFrame',
            'SplitterFrame': 'QSplitter',
            'Widget': 'QWidget',
            'MDI Area': 'QMdiArea',
            'Dock Widget': 'QDockWidget',
            'Quick Widget': 'QQuickWidget',
            'Web View': 'QWebEngineView'
        }}, {"group":"Input Widgets", "widgets":{
            'Combo Box': 'QComboBox',
            'Font Combo Box': 'QFontComboBox',
            'Line Edit': 'QLineEdit',
            'Text Edit': 'QTextEdit',
            'Plain Text Edit': 'QPlainTextEdit',
            'Spin Box': 'QSpinBox',
            'Double Spin Box': 'QDoubleSpinBox',
            'Time Edit': 'QTimeEdit',
            'Date Edit': 'QDateEdit',
            'Date/Time Edit': 'QDateTimeEdit',
            'Dial': 'QDial'
        }}, {"group":"Display Widgets", "widgets":{
            'Label': 'QLabel',
            'Text Browser': 'QTextBrowser',
            'Graphics View': 'QGraphicsView',
            'Calender Widget': 'QCalendarWidget',
            'LCD Number': 'QLCDNumber',
            'Progress Bar': 'QProgressBar',
            'OpenGL Widget': 'QOpenGLWidget'
        }}]

    def showEvent(self, event):
        # 注册控件
        global context
        exts = context.find_extension("UIPrototype::Widget")
        for ext in exts:
            makeui.RegWidget(ext.name(), ext.properties(), ext.create_child_methods(), ext.create_widget)

            b_added = False
            for group in self.widgets:
                if group['group'] == ext.group():
                    group['widgets'][ext.name()] = ext.show_name()
                    b_added = True
                    break
            
            if b_added == False:
                group = ext.group()
                groupw = {'group': group, 'widgets': {ext.show_name(): ext.name()}}
                #groupw[group] = {}
                #groupw[group][ext.name()] = ext.show_name()

                self.widgets.append(groupw)
                
        self.create_widget_tab()
        super().showEvent(event)

    def create_widget_tab(self):
        toolbox = QToolBox()
        self.setWidget(toolbox)

        for group in self.widgets:
            group_widget = self.create_widgets()
            group_name = group['group']
            for widget_show_name in group['widgets']:
                self.add_action( group_widget, widget_show_name, group['widgets'][widget_show_name])
            toolbox.addItem(group_widget, group_name)

    def create_widgets(self):
        widget = QWidget()
        layout = QVBoxLayout(widget)
        widget.setLayout(layout)

        return widget
    def add_action(self,  widget, show_name, class_name):
        button = QPushButton(show_name)
        widget.layout().addWidget(button)
 
        obj = ActionNewWidget()
        obj._new_type = class_name
        self.objs.append(obj)
        button.pressed.connect(obj.on_add_widget2)

class WidgetExploreExtension:
    def add_pane(self, frame):
        global _dataexplore_view
        self._dock1 = WidgetExploreDock()
        _dataexplore_view = self._dock1
        self._dock1.setWindowTitle('Widget Explore')
        frame.addDockWidget(Qt.RightDockWidgetArea, self._dock1)

        global _frame
        _frame = frame

def on_select_item(event, node):
    global g_cur_select_node
    g_cur_select_node = []
    g_cur_select_node.append(node)

def on_select_items(event, node_list):
    global g_cur_select_node
    g_cur_select_node = node_list


def OnRootNodeNew(event, node):
    global context
    data_service = context.find_service("DataService")
    root_node =  data_service.root_node()
    if not root_node:
        return 

    new_node = data_service.create_node("ResourceGroup", "ResourceGroup")
    root_node.add_child(new_node)
        
def OnAddNewChild(event, node, child):
    widget_sel = child.get_prop("class")

    # 特殊属性
    if widget_sel == 'QDockWidget':
        if 'POS::DockWidgetArea' not in child.get_props():
            child.set_prop('POS::DockWidgetArea', 'Left')
            child.set_prop('POS::DockGroupId', '0') 
    else:
        parent = node
        if parent.get_prop('class') == 'QGridLayout':
            if 'POS::rowspan' not in child.get_props():
                child.set_prop('POS::row', '0')
                child.set_prop('POS::col', '0')
                child.set_prop('POS::rowspan', '1')
                child.set_prop('POS::colspan', '1')
        elif parent.get_prop('class') in ['QTableView', 'QTreeView', 'QListView', 'QHeaderView', 'QUndoView', 'QColumnView']:
            if 'POS::row' not in child.get_props():
                child.set_prop('POS::row', '0')
                child.set_prop('POS::col', '0')
        elif parent.get_prop('class') == 'QTabWidget':
            if 'POS::TabName' not in child.get_props():
                child.set_prop('POS::TabName', 'tab')
        
    if widget_sel == 'QMenu':
        if 'Data::Icon' not in child.get_props():
            child.set_prop('Data::Icon', '%PROJECT%/../icon/down.png')
    if widget_sel == 'QTableView' or widget_sel == 'QTreeView' or widget_sel == 'QListView' or widget_sel == 'QHeaderView' or widget_sel == 'QUndoView' or widget_sel == 'QColumnView':
        if 'Data::BindData' not in child.get_props():
            child.set_prop('Data::BindData', '[["aaa", "bbb", "ccc"], ["a", "b", "c"], ["-a1", "b1", "c1"], ["abb", "bbb", "cbb"], ["-a2", "b2", "c2"]]')
    if widget_sel == 'QPlainTextEdit':
        if 'Data::BindText' not in child.get_props():
            child.set_prop('Data::BindText', 'Hello Text!!')

config = {
    'pluginid': 'UIPrototype::UI::Menu',
    # 菜单扩展
    #  文件|新建  文件|打开   文件|保存   文件|另存为   文件|关闭
    # 工具条扩展
    #    新建  打开  保存  另存为  关闭 | 新建页面
    "extensions" : [
        {
            "name": "PL::Basic::Pane",
            "id": "UIPrototype::Basic::Pane::WidgetExplore",
            "impl": WidgetExploreExtension()
        },
        {
            "name": "PL::Basic::ToolBar",
            "id": "UIPrototype::Basic::ToolBar::OpenSave",
            "impl": UIMainFileMenu()
        },
        {
            "name": "PL::Basic::ToolBar",
            "id": "UIPrototype::Basic::ToolBar::AddPage",
            "impl": UIMainAddPageMenu()
        },
        {
            "name": "PL::Basic::Menu",
            "id": "UIPrototype::Basic::Menu::OpenSave",
            "impl": UIMainFileMenu()
        },
        {
            "name": "DataExplore::DataNode::DragAction",
            "id": "UIPrototype::DataExplore::DataNode::DragAction::Resource",
            "impl": UIResourceDrag()
        }
    ],
    "subscribes" : [
        {
            "name": 'event::DataNode::Select',
            "define": on_select_item
        },
        {
            "name": 'event::DataNode::Select::items',
            "define": on_select_items
        },
        {
            "name": 'event::NewRootDataNode',
            "define": OnRootNodeNew
        },
        {
            "name": 'event::DataNode::Modify::AddChild',
            "define": OnAddNewChild
        }
    ]
}